ident = '$Id: base.py 109 2006-06-05 18:46:37Z trevor $'
'''Defines the base rex objects class. All rex objects are derived from this class to
standerdize the xml serialization process.
Child classes define their own data dictionary with the properties they are interested in.
'''
# binders imported to get the instance class
import common
from   	xml.sax 	import saxutils
from 	xml.dom		import minidom

#################
ROT_NONE	= 0
ROT_NUMBER	= 100
ROT_TEXT	= 101
ROT_TEXTHTML= 102 # all text based
ROT_EDITOR	= 103 # not used anymore?
ROT_CHOICE	= 104
ROT_DATE	= 105
ROT_BOOL	= 106
ROT_FREQ	= 107
ROT_MEMBERSHIP = 108
ROT_SUBS	= 109
ROT_BLOCKS	= 110
ROT_INS		= 111
ROT_QUESTIONS = 112
ROT_NOTIFIERS = 113
ROT_EMAIL	= 114

READONLY	= True
READWRITE	= False

CUSTOM		= True
NOT_CUSTOM	= True
FILE_UPLOAD	= True
NO_FILE_UPLOAD	= True

DIRTY_ONLY  = True

#################
class object:
	'''Base class for rex objects. This class cannot be instantiated by itself.'''
	def __init__( self, account, module, xmlstring = None ):
		'''Initialize the object.
		Optionally, an XML DOM can be provided to load the object from. Also, an account
		can be provided to be used when manipulating the object.'''
		self.module	= module
		self.account= account
		self.editor = None
		if xmlstring is not None:
			#print "rex.base.object parsing", self
			self.fromxml( xmlstring )

	def __getitem__( self, key ):
		'''Enables the object["property"] usage.'''
		for variable in self.data:
			#common.dprint("Looking for Key ", key )
			if variable['name'] == key:
				#common.dprint("Found ", variable['name'] )
				return variable['value']
		raise AttributeError, "No attribute "+ key

	def __setitem__( self, key, value, dirty = True ):
		'''Enables the object["property"]=value usage.'''
		# ignore namespaces
		# if key[:6] == 'xmlns:': return
# 		texthtml_offset = None
# 		if key[:5] == 'text:':
# 			texthtml_offset = 0
# 			key = key[5:]
# 		elif key[:5] == 'html:':
# 			texthtml_offset = 1
# 			key = key[5:]
		# find it in the data
		for variable in self.data:
			if variable['name'] == key:
				variable['dirty'] = dirty
				try:
					# if texthtml_offset is None:
						#common.dprint( "setting ", key, "to", value )
					variable['value'] = value
					# else:
					# 	variable['value'][texthtml_offset] = value
					return
				except:
					common.show_error("Failed to set the variable value key[%s] value[%s] variable[%s]" % (key, value, variable), False)
					return
		# not found, it must be a custom variable
		variable = {
			'name':			key,
			'value':		value,
			'label':		key,
			'type':			ROT_TEXT,
			'rw':			True,
			'file_upload':	False,
			'options':		None,
			'custom':		True,
			'dirty':		dirty
		}
		# modify to texthtml if it is a dual variable
		# if texthtml_offset is not None:
# 			variable['type'] = ROT_TEXTHTML
# 			if texthtml_offset == 0:
# 				variable['value'] = [ value, '']
# 			else:
# 				variable['value'] = [ '', value ]
		self.data.append( variable )

	def set_clean( self ):
		for variable in self.data:
			variable['dirty'] = False

	def toxml( self, dirty_only = False ):
		'''Returns the XML representation of the rex object.'''
		attributes = []
		for variable in self.data:
			common.dprint( "toxml checking" , variable['name'] , variable['dirty'] , variable['value'] )
			# What variables always go regardless
			if ( dirty_only and ( \
					variable['dirty'] or \
					variable['name'] == 'id' or \
					variable['name'] == 'binder_id' or \
					variable['name'] == 'instance_name' or \
					variable['name'] == 'instance_id'
				) ) or not dirty_only:
				common.dprint("Type:", variable['type'])
				common.dprint("Name:", variable['name'])
				common.dprint("value:", variable['value'])
				# try:
# 					common.dprint("value[0]:", variable['value'][0])
# 					common.dprint("value[1]:", variable['value'][1])
# 				except:
# 					pass
# 				if variable['type'] == ROT_TEXTHTML:
# 					attributes.append( "%s_text=%s" % ( variable['name'], saxutils.quoteattr( variable['value'][0] ) ) )
# 					attributes.append( "%s_html=%s" % ( variable['name'], saxutils.quoteattr( variable['value'][1] ) ) )
# 				else:
					#print "toxml adding", variable['name'], variable['dirty'], variable['value']
				attributes.append( "%s=%s" % ( variable['name'], saxutils.quoteattr( variable['value'] ) ) )
		sdom = ' '.join( attributes )
		sdom = "<" + self.object_name + " " + sdom + " />"
		return sdom

	def fromxml( self, xmlstring ):
		'''Loads the object's properties from an XML DOM.'''
		try: xmlstring = xmlstring.encode( 'utf-8' )
		except: common.dprint('** Failed to encode utf-8, skipping', False)
		xmlstring = common.prepare_xml( xmlstring )
		# We want exceptions here to boil up
		sdom 			  = minidom.parseString( xmlstring )
		if not sdom :
			common.dprint( "%s did not parse properly" % ( xmlstring ) )
		snode			  = sdom.firstChild
		for attrib in snode.attributes.items():
			k , v = attrib
			#~ common.dprint("fromxml k:", k)
			#~ v = unicode( v.decode('utf-8') )
			#~ common.dprint("fromxml v type:", type( v ) )
			#~ common.dprint("fromxml v:", v)
			self.__setitem__( k, v, False )
			del attrib
		del snode
		del sdom

	def create( self, new_name = None ):
		'''Create a new object on the server and sets the ID'''
		self['id'] = "0"
		if new_name is None:
			self['name'] = "New %s" % self.object_name
		else:
			self['name'] = new_name
		self['id'] = self.save()

	def clone( self ):
		'''Clone this object on the server and get the new object ID'''
		return self.__execute( "clone", ID=self['id'] )

	def	save( self ):
		'''Saves the object on the server'''
		dom = self.toxml( DIRTY_ONLY )
		return self.__execute( "save", dom=dom )

	def	save2( self ):
		'''Temporary fix to call save2 instead'''
		dom = self.toxml( DIRTY_ONLY )
		return self.__execute( "save2", dom=dom )

	def delete( self ):
		'''Deletes the object on the server'''
		return self.__execute( "delete", ID=self['id'])

	def __execute( self, *args, **kwargs ):
		'''Handles all method execution requests for the object.'''
		if self.account is None:
			raise Exception, "No account set for " + self.object_name + " object."
		method = self.object_name + "_" + args[0]
		return self.account.execute( self.module, method, **kwargs )

	def execute( self, *args, **kwargs ):
		'''Handles all method execution requests for the object.'''
		if self.account is None:
			raise Exception, "No account set for " + self.object_name + " object."
		method = self.object_name + "_" + args[0]
		return self.account.execute( self.module, method, **kwargs )
